/*
 *  Arrow
 *
 *  Created by David Giovannini on 1/5/07.
 *  Copyright 2007 Software by Jove. All rights reserved.
 *
 */
 
#include "SBJ/Arrow/Channel.h"
#include "SBJ/Interfaces/ExceptionCounter.h"
#include "SBJ/Arrow/SynchronousMsg.h"
#include "SBJ/Arrow/TimerFeed.h"
#include "MockMessage.h"

#include <boost/test/auto_unit_test.hpp>

class ThrowingSyncMsg : public SBJ::Arrow::SynchronousMsg
{
public:
	ThrowingSyncMsg( const SBJ::Arrow::Topic& topic )
	: SBJ::Arrow::SynchronousMsg( topic )
	{
	}
	
	inline void invoke( Subscriber* )
	{
		throw std::exception();
	}
};

BOOST_AUTO_TEST_CASE(Excpetion)
{
	::printf("Exception\n");
	SBJ::ExceptionCounter::Ptr excCounter ( new SBJ::ExceptionCounter );
	SBJ::Arrow::Channel channel( excCounter );
	channel.start();
	int i = 0;
	int j = 0;
	void* s1 = &i;
	void* s2 = &j;
	SBJ::Arrow::Publication& waitPub = channel.publish< ThrowingSyncMsg >();
	SBJ::Arrow::Subscription sub1 = channel.makeTypedSubscription< ThrowingSyncMsg >( s1, "test" );
	sub1.activate();
	SBJ::Arrow::Subscription sub2 = channel.makeTypedSubscription< ThrowingSyncMsg >( s2, "test" );
	sub2.activate();
	ThrowingSyncMsg msg( waitPub.getTopic( "test" ) );
	channel.onMessage( msg );
	msg.wait();
	BOOST_CHECK_EQUAL(2, excCounter->getExceptionCount() );
}

BOOST_AUTO_TEST_CASE(Priority)
{
	::printf("Priority\n");
	// Create the channel
	SBJ::Arrow::Channel channel( -1, 0, 2 );

	// Publish our message type
	SBJ::Arrow::Publication& pub = channel.publish< MockMessage >();

	// Create the messages
	volatile const char* hit = 0;
	MockMessage msg0( hit, pub.getTopic< MockMessage >(), 0 );

	MockSubscriber subscriber1;
	MockMessage msg1( hit, pub.getTopic< MockMessage >(), 1, &subscriber1 );

	// Push the messages where 1 is not last
	channel.onMessage( msg0 );
	channel.onMessage( msg0 );
	channel.onMessage( msg1 );
	channel.onMessage( msg0 );
	channel.onMessage( msg0 );

	// Start dequeuing
	channel.start();

	::test_sleep( .5 );
	// test to make certain low priority is executed last
	BOOST_CHECK_EQUAL( MockMessage::hit_execute_HasTest, const_cast<char*>(hit) );
}

BOOST_AUTO_TEST_CASE(TimerFeed)
{
	::printf("TimerFeed\n");
	// Create the channel
	SBJ::Arrow::Channel channel;
	channel.start();

	// Create the timer
	SBJ::Arrow::TimerFeed::Ptr timer( new SBJ::Arrow::TimerFeed() );
	channel.addFeed( timer );

	// Publish our message type
	SBJ::Arrow::Publication& pub = channel.publish< MockMessage >();

	// Creat the message
	volatile const char* hit = 0;
	MockMessage msg( hit, pub.getTopic< MockMessage >() );

	// And test
	timer->addMessage( msg, 2.0 );
	::test_sleep( 1.0 );
	BOOST_CHECK_EQUAL( MockMessage::hit_none, const_cast<char*>(hit) );
	::test_sleep( 1.5 );
	BOOST_CHECK_EQUAL( MockMessage::hit_execute, const_cast<char*>(hit) );
}
